/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package display;

import core.file.FileBroker;
import entity.DungeonEntity;
import entity.Orientation;
import enviro.Tile;
import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.IOException;
import java.util.HashMap;
import javax.swing.JPanel;

/**
 * TileDisplay is an extension of the JPanel bean.  It is primarily intended
 * as an interactive display to allow for tile customization.  This component
 * includes five 'drop zones' in which a user can insert DungeonEntities with
 * the drag-and-drop interface.
 * 
 * @author timon
 */
public class TileDisplay extends JPanel {
    
    // <editor-fold defaultstate="collapsed" desc="Member Variables">
        private Tile tile = new Tile(); // The tile currently residing in the 
                                        // panel.
        
        private boolean tileLoaded = false; // Indicates whether there is a 
                                            // tile currently in memory
        
        // Stores all images used in this panel since it's last load.
        private HashMap<String, Image> imagemap = new HashMap<String, Image>();
        
    // </editor-fold>
        
    // <editor-fold defaultstate="collapsed" desc="Constructor(s)">
        /**
         * CONSTRUCTOR <br/><br/>
         * 
         * The default constructor activates the TileDisplay for use in the
         * user interface.
         */
        public TileDisplay() {
            
            // Make this component visible.
            setVisible(true);
        }
    // </editor-fold>
        
    // <editor-fold defaultstate="collapsed" desc="API">    
    
        /**
         * Loads a dungeon tile into memory for display and manipulation.
         * 
         * @param tile
         *   The dungeon tile to be subjected to manipulation
         * 
         * @throws IOException 
         */
        public void loadTile(Tile tile) throws IOException {
            
            // Set tile in memory and indicate that there is a tile in memory
            this.tile = tile;
            tileLoaded = true;
            
            // Refresh the image on the screen.
            repaint();
            
            imagemap.put(tile.getImagepath(), FileBroker.readImage(
                    tile.getImagepath()));
            
            setLayout(new BorderLayout());
            
        }
        
        
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
               
            if (tileLoaded) {
                
            Graphics2D g2d = (Graphics2D) g;
            
            
                // Absorb the image from the map
                String filename = tile.getImagepath();
                Image tileImage = imagemap.get(filename);

                // Draw the absorbed image in the appropriate place
                g2d.drawImage(tileImage,
                                0,0,
                                this.getWidth(), this.getHeight(),this);

                // Draw the DungeonEntities tied to this tile
                try {

                    g2d = paintTileEntities(g2d);

                }
                catch (IOException ioe){}
                
            }
        }
        
        public void loadDungeonEntity(DungeonEntity entity){
            
            entity.place(tile);
        }
        
        public Tile getTile() {
            return this.tile;
        }
        
        public void refresh() {
            repaint();
        }
    // </editor-fold>
        
    // <editor-fold defaultstate="collapsed" desc="Private Utilities">
        /**
         * Scan the tile for Entities, and in turn scan those entities for images.
         * 
         * Images found will be added into local memory for speedy retreival
         * @param tile
         *   This is the tile that will be scanned
         * 
         * @return 
         *   Returns false if no valid strings were found (does not indicate 
         * operational failure - the return is used to report whether any images 
         * are specified.
         * 
         * @throws IOException 
         *   Throws an IO Exception if something bad went down during the read
         */
        private boolean scanTileForImages(Tile tile) throws IOException {
            
            // this is our flag for valid measurement
            boolean valid = false;
            
            // Scan each slot in the tile for images
            valid = (scanEntityForImages(tile.getDungeonEntity()) || 
                    valid == true) ? true : false;
            
            return valid;
        }
        
        
        /**
         * Scan an entity for images, and add those images into local memory.
         * 
         * @param entity
         *   This is the DungeonEntity being scanned for images
         * 
         * @return 
         *   Returns false only if no filepaths are specified, otherwise reports true.
         *   (note that this does not indicate operational success or failure)
         * 
         * @throws IOException 
         *   Throws an IOException if something bad went down during the read.
         */
        private boolean scanEntityForImages(DungeonEntity entity) throws IOException {
            
            // We use this 'dummy' to compare unitilized entities, that way we
            // can recognize and reject uninitlized entities and skip past them.            
            // This is a flag to indicate whether or not anything was updated.
            boolean valid = false;
            
            // skip past uninit'd 
            if (entity == null) return false;
                            
            String thisPath = entity.getOrientationImagePath(Orientation.NORMAL);
            valid = (commitImage(thisPath) || valid == true) ? true : false;

            thisPath = entity.getOrientationImagePath(Orientation.DEGREES_90);
            valid = (commitImage(thisPath) || valid == true) ? true : false;

            thisPath = entity.getOrientationImagePath(Orientation.DEGREES_180);
            valid = (commitImage(thisPath) || valid == true) ? true : false;

            thisPath = entity.getOrientationImagePath(Orientation.DEGREES_270);
            valid = (commitImage(thisPath) || valid == true) ? true : false;
            
            return valid;
        }
        
        /**
         * Commit an image to the image map with using filepath
         * 
         * This method will make sure the path is not empty or null, 
         * verify that is is unique to prevent over-writing of existing values,
         * and then commit the change.
         * 
         * @param imagePath
         * 
         * @return 
         *   TRUE == The string was valid
         *   FALSE == The string was empty (this does NOT mean the operation failed!)
         */
        private boolean commitImage(String imagePath) throws IOException {
            
            boolean valid = false;
            
            if (!(imagePath.equals(""))) {
                             
                valid = true;
                
                if (!(imagemap.containsKey(imagePath))) {

                    imagemap.put(imagePath, FileBroker.readImage(imagePath));
                }
            }
            
            return valid;
        }
        
            
        
        
        
        /**
         * Assist paint manager by painting all of the dungeon entities
         * on a given tile
         * 
         * @param graphics
         *   The graphics 'pane' on which this is to be drawn
         * @param x
         *   The x grid point of the tile
         * @param y
         *   The y grid point of the tile
         * 
         * @return
         *   The altered graphics object is returned.
         */
        private Graphics2D paintTileEntities(Graphics2D g2d) throws IOException {
            
            Tile scanningTile = tile;
            
            if (!(scanTileForImages(scanningTile))) return g2d;
            
            g2d = paintEntity(0, 0, g2d, scanningTile);
            return g2d;
        }
        
        private Graphics2D paintEntity(int x, int y, Graphics2D g2d, Tile scanningTile) throws IOException {
            
            DungeonEntity scanningEntity = scanningTile.getDungeonEntity();
            
            if (scanningEntity == null) return g2d;
            
            if (scanEntityForImages(scanningEntity)) {
                
                if (!(scanningEntity.getOrientationImagePath(scanningEntity.getOrientation()).equals(""))) {

                    // nab the image from the map
                    String path = scanningEntity.getOrientationImagePath(
                            scanningEntity.getOrientation());
                    Image entityImage = imagemap.get(path);
                    
                    // draw the image on the plate
                    g2d.drawImage(entityImage,
                            0,0,
                            this.getWidth(), this.getHeight(),
                            this);
                    return g2d;
                }
            }
            
            return g2d;
        }
        
        // </editor-fold>
        
        
     
}
